package net.loogn.stardust.server;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.sun.xml.internal.ws.commons.xmlutil.Converter;
import net.loogn.stardust.common.model.ServerNodeModel;
import net.loogn.stardust.common.model.ServiceContractModel;
import net.loogn.stardust.common.utils.ObjectGenerator;

import javax.jws.soap.SOAPBinding;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.*;

/**
 * Created by Administrator on 2017/4/7.
 */
class ActionManager {
    static HashMap<String, ActionWrapper> actionDict;


    static List<ServiceContractModel> loadActions(ServerNodeModel node, Set<Class> serviceClasses) throws ClassNotFoundException, IllegalAccessException, InstantiationException {

        List<ServiceContractModel> contractList = new ArrayList<>();

        actionDict = new HashMap<>();
        for (Class cls : serviceClasses) {
            String controllerName = null;
            String controllerDesc = null;
            StardustName clsAnnotation = (StardustName) cls.getAnnotation(StardustName.class);
            if (clsAnnotation != null) {
                controllerName = clsAnnotation.name().toLowerCase();
                controllerDesc = clsAnnotation.description();
            }
            if (controllerName == null || controllerName.equals("")) {
                controllerName = cls.getSimpleName().toLowerCase();
                if (controllerName.endsWith("service")) {
                    controllerName = controllerName.substring(0, controllerName.length() - 7);
                }
            }
            Object obj = cls.newInstance();
            for (Method method : cls.getMethods()) {
                if (method.getDeclaringClass().equals(cls) && !method.getReturnType().getName().equals("void")) {
                    Class[] psTypes = method.getParameterTypes();
                    if (psTypes.length <= 1) {
                        String actionName = null;
                        String actionDesc = null;
                        StardustName methodAnnotation = method.getAnnotation(StardustName.class);
                        if (methodAnnotation != null) {
                            actionName = methodAnnotation.name().toLowerCase();
                            actionDesc = methodAnnotation.description();
                        }
                        if (actionName == null || actionName.equals("")) {
                            actionName = method.getName().toLowerCase();
                        }
                        //契约
                        if (!controllerName.equalsIgnoreCase("__internal")) {
                            ServiceContractModel contract = buildContract(node, cls, method, controllerName, controllerDesc, actionName, actionDesc);
                            contractList.add(contract);
                        }
                        String path = "/" + controllerName + "/" + actionName;
                        actionDict.put(path, new ActionWrapper(obj, method, psTypes.length));
                    }
                }
            }
        }
        return contractList;
    }

    private static ServiceContractModel buildContract(ServerNodeModel node, Class type, Method method, String controllerName, String controllerDesc, String actionName, String actionDesc) {
        ServiceContractModel contract = new ServiceContractModel();
        contract.setServerNodeId(node.getId());
        contract.setControllerName(controllerName);
        contract.setActionName(actionName);
        contract.setControllerDescription(controllerDesc);
        contract.setActionDescription(actionDesc);

        //contract.setParams("java版本未实现...");
        //参数JSON
        ObjectGenerator paramsGenerator = new ObjectGenerator();
        Parameter[] Parameters = method.getParameters();
        if (Parameters == null || Parameters.length == 0) {
            //空参数
        } else if (Parameters.length == 1) {
            Parameter p1 = Parameters[0];
            Object paramsObject = paramsGenerator.GenerateObject(p1.getType(), p1.getParameterizedType());
            String resultJson = JSON.toJSONString(paramsObject, true);
            contract.setParams(resultJson);
        } else {
            contract.setParams("服务方法错误：参数个数只能是0个或1个");
        }
        //返回值JSON
        ObjectGenerator resultGenerator = new ObjectGenerator();
        Object resultObject = resultGenerator.GenerateObject(method.getReturnType(), method.getGenericReturnType());
        String resultJson = JSON.toJSONString(resultObject, true);
        contract.setResult(resultJson);
        return contract;
    }

    static ActionWrapper getActionWrapper(String path) {
        return actionDict.get(path);
    }

    static class ActionWrapper {
        private Method _method;
        private Object _obj;
        private int _psCount;
        private Parameter[] _params;

        public ActionWrapper(Object obj, Method method, int psCount) {
            _obj = obj;
            _method = method;
            _psCount = psCount;
            _params = method.getParameters();
        }

        public Object invoke(String json) throws InvocationTargetException, IllegalAccessException {
            Object[] ps = fatchParams(json);
            Object result = _method.invoke(_obj, ps);
            return result;
        }

        private Object[] fatchParams(String json) {
            if (_params.length == 0) {
                return new Object[]{};
            }
            //单个类
            if (_params.length == 1) {
                Object arg0 = null;
                //字符串不能直接parseObject，呵呵
                if (_params[0].getType() == String.class) {
                    arg0 = json;
                } else {
                    arg0 = JSON.parseObject(json, _params[0].getParameterizedType());
                }
                return new Object[]{
                        arg0
                };
            }
            return null;
        }
    }
}

